#include "goal.h"

namespace IAlib
{

Goal::Goal()
{
    m_Name = "";
    m_priority = 0;
    m_Satisfied = false;
}
//-----------------------------------------------------------
Goal::Goal( const QString& Name )
{
    m_Name = Name;
    m_priority = 0;
    m_Satisfied = false;
}
//-----------------------------------------------------------
Goal::Goal( const QString& Name, const QList<Plan>&  plans )
{
    m_Name = Name;
    for (int i = 0; i < m_plans.size(); i++)
    {
        Plan * newPlan = new Plan(plans[i]);
        m_plans.append(newPlan);
    }
    m_priority = 0;
    m_Satisfied = false;
}
//-----------------------------------------------------------
Goal::Goal( const Goal & goal )
{
    m_Name = goal.m_Name;
    for (int i = 0; i < goal.m_plans.size(); i++)
    {
        Plan * newPlan = new Plan(*goal.m_plans[i]);
        m_plans.append(newPlan);
    }
    m_priority = goal.m_priority;
    m_Satisfied = goal.m_Satisfied;
    m_preconditions = goal.m_preconditions;
    m_previous_goal = goal.m_previous_goal;
}

//-----------------------------------------------------------------

Goal& Goal::operator=(const Goal& goal)
{
	m_Name = goal.m_Name;
	for (int i = 0; i < m_plans.size(); i++)
    {
        delete(m_plans[i]);
    }
	m_plans.clear();
    for (int i = 0; i < goal.m_plans.size(); i++)
    {
        Plan * newPlan = new Plan(*goal.m_plans[i]);
        m_plans.append(newPlan);
    }
    m_priority = goal.m_priority;
    m_Satisfied = goal.m_Satisfied;
    m_preconditions = goal.m_preconditions;
    m_previous_goal = goal.m_previous_goal;
	return *this;
}

//-----------------------------------------------------------------
Goal::~Goal()
{
    for (int i = 0; i < m_plans.size(); i++)
    {
        delete(m_plans[i]);
    }
}

///////////////////////////////////////////////////////////////////////////////////////////////////

void Goal::addPlan( const Plan&  plan )
{
    Plan * newPlan = new Plan(plan);
    m_plans.append(newPlan);
}

///////////////////////////////////////////////////////////////////////////////////////////////////

void Goal::addPrecondition(const Fact &fact)
{
    m_preconditions.insert(m_preconditions.size(), fact);
}

//////////////////////////////////////////////////////////////////////////////////////////////////

void Goal::addPreviousGoal(const QString &goalName)
{
    m_previous_goal.append(goalName);
}

///////////////////////////////////////////////////////////////////////////////////////////////////

int Goal::removePlan(const QString& PlanName)
{
    int i = 0;
    while (i < m_plans.size())
    {
        if (m_plans[i]->getName() == PlanName)
        {
            delete(m_plans[i]);
            m_plans.removeAt(i);
            return 1;
        }
        i++;
    }
    return -1;
}

///////////////////////////////////////////////////////////////////////////////////////////////////

void Goal::removePrecondition(const QString &factName)
{
    int i = 0;
    while (i < m_preconditions.size())
    {
        if (m_preconditions[i].getFactName() == factName)
        {
            break;
        }
        i++;
    }
    m_preconditions.removeAt(i);
}

///////////////////////////////////////////////////////////////////////////////////////////////////

void Goal::removePreviousGoal(const QString &goalName)
{
    m_previous_goal.removeAt(m_previous_goal.indexOf(goalName));
}

///////////////////////////////////////////////////////////////////////////////////////////////////

bool Goal::hasPrecondition(const QString &factName)
{
    int i = 0;
    while (i < m_preconditions.size())
    {
        if (m_preconditions[i].getFactName() == factName)
        {
            return true;
        }
        i++;
    }
    return false;
}

///////////////////////////////////////////////////////////////////////////////////////////////////

void Goal::reset()
{
    m_Satisfied = false;
}

//////////////////////////////////////////////////////////////////////////////////////////////////

void Goal::clear()
{
	m_Name = "";
	m_priority = 0;
	m_preconditions.clear();
	m_previous_goal.clear();
	for (int i = 0; i < m_plans.size(); i++)
    {
        delete(m_plans[i]);
    }
	m_plans.clear();
	m_Satisfied = false;
}

///////////////////////////////////////////////////////////////////////////////////////////////////

QDomElement Goal::toXML(QDomDocument &doc)
{
    QDomElement ele = doc.createElement("goal");
    ele.setAttribute("priority", m_priority);
    ele.setAttribute("goalName", m_Name);
    QDomElement prec = doc.createElement("preconditions");
    for (int i = 0; i < m_preconditions.size(); i++)
    {
        prec.appendChild(m_preconditions[i].toXML(doc));
    }
    ele.appendChild(prec);
    QDomElement previous_goal = doc.createElement("previousGoal");
    for (int i = 0; i < m_previous_goal.size(); i++)
    {
        QDomElement goal_name = doc.createElement("goalName");
        goal_name.appendChild(doc.createTextNode(m_previous_goal[i]));
        previous_goal.appendChild(goal_name);
    }
    ele.appendChild(previous_goal);
    QDomElement plans = doc.createElement("plans");
    for (int i = 0; i < m_plans.size(); i++)
    {
        plans.appendChild(m_plans[i]->toXML(doc));
    }
    ele.appendChild(plans);
    return ele;
}

void Goal::fromXML(QDomElement element, QMap<QString, Action*> actions)
{
    m_Name = element.attribute("goalName","");
    m_priority = element.attribute("priority","").toInt();
    QDomNode Node = element.firstChild();
    while (!Node.isNull())
    {
        QDomElement ele = Node.toElement();
        if (ele.tagName() == "plans")
        {
            QDomNode planNode = ele.firstChild();
            while (!planNode.isNull())
            {
                Plan plan;
                plan.fromXML(planNode.toElement(),actions);
                addPlan(plan);
                planNode = planNode.nextSibling();
            }
        }
        else if (ele.tagName() == "preconditions")
        {
            QDomNode precNode = ele.firstChild();
            while (!precNode.isNull())
            {
                Fact f;
                f.fromXML(precNode.toElement());
                addPrecondition(f);
                precNode = precNode.nextSibling();
            }
        }
        else if (ele.tagName() == "previousGoal")
        {
            QDomNode previous_goalNode = ele.firstChild();
            while (!previous_goalNode.isNull())
            {
                addPreviousGoal(previous_goalNode.toElement().text());
                previous_goalNode = previous_goalNode.nextSibling();
            }
        }
        Node = Node.nextSibling();
    }
}

//-------------------------------------------

QByteArray Goal::toByteArray()
{
	QByteArray byte_array;
	QDataStream data(&byte_array, QIODevice::WriteOnly);
	data<<m_Name;
	data<<m_priority;
	data<<m_plans.size();
	for (int i = 0; i < m_plans.size(); i++)
	{
		QByteArray plan_byte_array = m_plans[i]->toByteArray();
		data<<plan_byte_array;
	}
	return byte_array;
}

//-------------------------------------------

void Goal::fromByteArray(QByteArray& byte_array)
{
	QDataStream data(&byte_array, QIODevice::ReadOnly);
	data>>m_Name;
	data>>m_priority;
	int nb_plan;
	data>>nb_plan;
	for (int i = 0; i < nb_plan; i++)
	{
		Plan plan;
		QByteArray plan_byte_array;
		data>>plan_byte_array;
		plan.fromByteArray(plan_byte_array);
		addPlan(plan);
	}
}


///////////////////////////////////////////////////////////////////////////////////////////////////*

void Goal::setName(const QString& Name)
{
    m_Name = Name;
}
//------------------------------
void Goal::setPriority(int priority)
{
    m_priority = priority;
}
//------------------------------
void Goal::Satified(bool satisfied)
{
    m_Satisfied = satisfied;
}

//------------------------------

QString Goal::getName() const
{
    return m_Name;
}
//------------------------------
int Goal::getPriority() const
{
    return m_priority;
}
//------------------------------
bool Goal::is_Satified() const
{
    return m_Satisfied;
}
//------------------------------
QList<Plan*> Goal::getPlans() const
{
    return m_plans;
}
//------------------------------
QList<Fact> Goal::getPreconditions() const
{
    return m_preconditions;
}
//------------------------------
QList<QString> Goal::getPreviousGoals() const
{
    return m_previous_goal;
}
//------------------------------
Plan* Goal::getPlan(const QString& PlanName)
{
    for (int i = 0; i < m_plans.size();i++)
    {
        if (m_plans[i]->getName() == PlanName)
        {
            return m_plans[i];
        }
    }
    return NULL;
}

}
